package jp.seraph.jsade.math;

/**
 * 角速度を表す構造体<br>
 * 単位はdegree/step
 * <br>
 * イミュータブルであり、すべてのメソッドに副作用はない
 *
 */
public class AngleVelocity {
    private AngleVelocity(Angle aBaseAngle, double aScaleFactor){
        mDegreeVelocity = aBaseAngle.getDegree() * aScaleFactor;
    }

    private AngleVelocity(double aDegree){
        mDegreeVelocity = aDegree;
    }

    /**
     * Angleを元にAngleVelocityのインスタンスを作成します。<br>
     * 生成されるAngleVelocityは、内部に元となったAngleと同じ値(Degree)を保持します。
     *
     * @param aBaseAngle 元になるAngle
     * @return 生成されたAngleVelocity
     */
    public static AngleVelocity create(Angle aBaseAngle){
        return AngleVelocity.create(aBaseAngle, 1.0);
    }

    /**
     * Angleと倍率を元にAngleVelocityのインスタンスを生成します。<br>
     * 生成されるAngleVelocityは、元になったAngleのgetDegreeメソッドの返り値に倍率をかけた値を保持します。
     *
     * @param aBaseAngle 元になるAngle
     * @param aScaleFactor 倍率
     * @return 生成されたAngleVelocity
     */
    public static AngleVelocity create(Angle aBaseAngle, double aScaleFactor){
        return new AngleVelocity(aBaseAngle, aScaleFactor);
    }

    /**
     * 引数に度数法による角度を与えて、AngleVelocityを作成する
     *
     * @param aDegree 度数法による角度[°]
     * @return 生成されたAngleVelocity
     */
    public static AngleVelocity createAsDegree(double aDegree){
        return new AngleVelocity(aDegree);
    }

    /**
     * 引数に弧度法による角度を与えて、AngleVelocityを作成する
     *
     * @param aRad 弧度法による角度[rad]
     * @return 生成されたAngleVelocity
     */
    public static AngleVelocity createAsRad(double aRad){
        return new AngleVelocity(Math.toDegrees(aRad));
    }

    /**
     * 角速度0であるインスタンス
     */
    public static final AngleVelocity ZERO = new AngleVelocity(0);

    private double mDegreeVelocity;

    /**
     * このAngleVelocityに引数のAngleVelocityを足したものを返す。
     *
     * @param aVelocity 角速度
     * @return 計算後のAngleVelocity
     */
    public AngleVelocity add(AngleVelocity aVelocity){
        return AngleVelocity.createAsDegree(this.getDegree() + aVelocity.getDegree());
    }

    /**
     * このAngleVelocityに、引数を度数法の角度として足したものを返す。
     *
     * @param aDegree 度数法による角度
     * @return 計算後のAngleVelocity
     */
    public AngleVelocity addDegree(double aDegree){
        return AngleVelocity.createAsDegree(mDegreeVelocity + aDegree);
    }

    /**
     * このAngleVelocityに、引数を弧度法の角度として足したものを返す。
     *
     * @param aRad 弧度法による角度[rad]
     * @return 計算後のAngleVelocity
     */
    public AngleVelocity addRad(double aRad){
        return AngleVelocity.createAsRad(this.getRad() + aRad);
    }

    /**
     * このAngleVelocityから引数のAngleVelocityを引いたものを返す。
     *
     * @param aVelocity
     * @return 計算後のAngleVelocity
     */
    public AngleVelocity subtract(AngleVelocity aVelocity){
        return AngleVelocity.createAsDegree(this.getDegree() - aVelocity.getDegree());
    }

    /**
     * このAngleVelocityから、引数を度数法の角度として引いたものを返す。
     *
     * @param aDegree
     * @return 計算後のAngleVelocity
     */
    public AngleVelocity subtractDegree(double aDegree){
        return AngleVelocity.createAsDegree(mDegreeVelocity - aDegree);
    }

    /**
     * このAngleVelocityから、引数を弧度法の角度として引いたものを返す。
     *
     * @param aRad
     * @return 計算後のAngleVelocity
     */
    public AngleVelocity subtractRad(double aRad){
        return AngleVelocity.createAsRad(this.getRad() - aRad);
    }

    /**
     * このAngleVelocityをaScaleFactor倍したものを返す。
     *
     * @param aScaleFactor 倍率
     * @return 計算後のAngleVelocity
     */
    public AngleVelocity scale(double aScaleFactor){
        return AngleVelocity.createAsDegree(mDegreeVelocity * aScaleFactor);
    }

    /**
     * このAngleVelocityが表す角度を度数法の角度として返す
     *
     * @return 度数法の角度[°]
     */
    public double getDegree(){
        return mDegreeVelocity;
    }

    /**
     * このAngleVelocityが表す角度を弧度法の角度として返す
     *
     * @return 弧度法の角度[rad]
     */
    public double getRad(){
        return Math.toRadians(mDegreeVelocity);
    }


    public boolean equals(Object arg0) {
        if(!(arg0 instanceof AngleVelocity))
            return false;

        AngleVelocity tArg = (AngleVelocity)arg0;
        return tArg.getDegree() == this.getDegree();
    }


    public int hashCode() {
        return (int)(Double.doubleToLongBits(mDegreeVelocity) & 0xFFFFFFFF);
    }


}
